﻿using Blm.Utils.Extensions;
using Language.Resource;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Sys;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;

namespace VisionCloud.Service.Sys
{
    public class PermissionService
    {
        public IUnitOfWork UnitOfWork { get; set; }
        public IStringLocalizer<ServiceResource> Localizer { get; set; }
        public ISysRolePermissionRepository SysRolePermissionRepository { get; set; }
        public ISysUserRoleRepository SysUserRoleRepository { get; set; }

        public ISysMenuRepository SysMenuRepository { get; set; }

        public ISysUserRepository SysUserRepository { get; set; }

        public ISysMenuFuncRepository SysMenuFuncRepository { get; set; }

        public MenuFuncService MenuFuncService { get; set; }

        #region 添加人员到App角色、App的项目角色 角色权限 角色的菜单 用户的角色菜单与菜单权限

        #region 角色权限关系基本操作

        public async Task<bool> Existed(SysRolePermissionDto model)
        {
            return await SysRolePermissionRepository.AnyAsync(p => p.RoleId == model.RoleId && p.MenuFuncId == model.MenuFuncId);
        }

        public async Task<ApiPageResult> GetRolePermissionPage(SysRolePermissionCondition conditon)
        {
            return await SysRolePermissionRepository.GetPage(conditon);
        }

        public async Task CreateRolePermission(SysRolePermissionDto model, Guid opeId)
        {
            var exists = await Existed(model);
            if (exists == true)
            {
                throw new OperationException(Localizer["YB0222"].Value);
            }

            var entity = model.CopyTo<SysRolePermission>();
            entity.RolePermissionId = Guid.NewGuid();
            entity.CreatedBy = opeId;
            entity.CreatedDate = DateTime.Now;
            entity.LastUpdatedBy = opeId;
            entity.LastUpdatedDate = DateTime.Now;

            SysRolePermissionRepository.Add(entity);
            await UnitOfWork.SaveChangesAsync();
        }

        public async Task DeleteRolePermission(Guid rolePermissionId, Guid opeId)
        {
            SysRolePermissionRepository.Update(t => t.RolePermissionId == rolePermissionId, d =>
            {
                d.IsDeleted = true;
                d.LastUpdatedBy = opeId;
                d.LastUpdatedDate = DateTime.Now;
            });

            await UnitOfWork.SaveChangesAsync();
        }

        public async Task UpdateRolePermission(SysRolePermissionDto model, Guid opeId)
        {
            var entity = model.CopyTo<SysRolePermission>();
            SysRolePermissionRepository.Update(entity);

            await UnitOfWork.SaveChangesAsync();
        }

        #endregion 角色权限关系基本操作

        #region 用户权限的操作即是对用户角色的管理

        /// <summary>
        /// 批量添加用户列表的成员到角色列表的角色
        /// </summary>
        /// <param name="listUser"></param>
        /// <param name="listRole"></param>
        /// <returns></returns>
        public async Task<int> AddUsersToRoles(List<SysUserRoleDto> listUserRole, Guid opeId)
        {
            var listSysUserRole = new List<SysUserRole>();
            foreach (var model in listUserRole)
            {
                var entity = await SysUserRoleRepository.Get(new SysUserRoleCondition() { UserId = model.UserId, RoleId = model.RoleId });
                if (entity != null)
                {
                    SysUserRoleRepository.Update(p => p.UserId == model.UserId && p.RoleId == model.RoleId, d =>
                    {
                        d.IsDeleted = false;
                        d.LastUpdatedBy = opeId;
                        d.LastUpdatedDate = DateTime.Now;
                    });
                }
                else
                {
                    entity = model.CopyTo<SysUserRole>();
                    entity.UserRoleId = Guid.NewGuid();
                    entity.CreatedBy = opeId;
                    entity.CreatedDate = DateTime.Now;
                    entity.LastUpdatedBy = opeId;
                    entity.LastUpdatedDate = DateTime.Now;
                    listSysUserRole.Add(entity);
                }
            }
            return await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 批量删除用户角色
        /// </summary>
        /// <param name="listUserRole"></param>
        /// <param name="opeId"></param>
        /// <returns></returns>
        public async Task<int> RemoveUsersRoles(List<SysUserRoleDto> listUserRole, Guid opeId)
        {
            foreach (var model in listUserRole)
            {
                var entity = await SysUserRoleRepository.Get(model.CopyTo<SysUserRoleCondition>());
                entity.IsDeleted = true;
                entity.LastUpdatedBy = opeId;
                entity.LastUpdatedDate = DateTime.Now;
                SysUserRoleRepository.Update(entity);
            }

            return await UnitOfWork.SaveChangesAsync();
        }

        #endregion 用户权限的操作即是对用户角色的管理

        #region 角色的权限

        /// <summary>
        /// 获取角色的权限列表
        /// </summary>
        /// <param name="roleList"></param>
        /// <returns></returns>
        public async Task<List<RoleMenuPermissionDto>> GetRolePermissions(List<Guid> roleList)
        {
            return await SysRolePermissionRepository.FindSysRolePermission(roleList);
        }

        #endregion 角色的权限

        #region 角色的菜单

        /// <summary>
        /// 获取角色的菜单列表
        /// </summary>
        /// <param name="roleList"></param>
        /// <returns></returns>
        public async Task<Dictionary<Guid, List<RoleMenuDto>>> GetRoleMenus(List<Guid> roleList)
        {
            Dictionary<Guid, List<RoleMenuDto>> dicRoleMenus = new Dictionary<Guid, List<RoleMenuDto>>();
            var permisionList = await SysRolePermissionRepository.FindSysRolePermission(roleList);
            foreach (var roleId in roleList)
            {
                var roleMenuList = permisionList
                    .Where(p => p.RoleId == roleId)
                    .Select(p => new RoleMenuDto
                    {
                        RoleId = p.RoleId,
                        RoleName = p.RoleName,
                        MenuId = p.MenuId,
                        MenuName = p.MenuName,
                        MenuLevel = p.MenuLevel,
                        MenuSort = p.MenuSort,
                        ParentMenuId = p.ParentMenuId,
                        ParentMenuName = p.ParentMenuName,
                        Icon = p.MenuIcon,
                        Url = p.MenuUrl,
                        Component = p.MenuComponent,
                    })
                    .Distinct(new RoleMenuDtoComparer()).OrderBy(p => p.RoleId).OrderBy(p => p.MenuId).OrderBy(p => p.MenuLevel).OrderBy(p => p.MenuSort)
                    .ToList();

                dicRoleMenus.Add(roleId, roleMenuList);
            }
            return dicRoleMenus;
        }

        public class RoleMenuDtoComparer : IEqualityComparer<RoleMenuDto>
        {
            public bool Equals(RoleMenuDto x, RoleMenuDto y)
            {
                return x.MenuId == y.MenuId;
            }

            public int GetHashCode(RoleMenuDto obj)
            {
                if (obj == null)
                {
                    return 0;
                }
                else
                {
                    return obj.ToString().GetHashCode();
                }
            }
        }

        #endregion 角色的菜单

        #region 用户的角色 用户的菜单与权限

        #region 用户的角色

        /// <summary>
        /// 用户的角色
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<Guid>> GetUserRoles(Guid userId)
        {
            var userRoleList = await SysUserRoleRepository.FindSysUserRole(userId);
            var roleList = userRoleList.Select(p => p.RoleId).ToList();
            return roleList;
        }

        public async Task<List<SysRoleDto>> GetUserRoleWithName(Guid userId)
        {
            Dictionary<Guid, string> dicRole = new Dictionary<Guid, string>();
            var userRoleList = await SysUserRoleRepository.FindSysUserRole(userId);
            return userRoleList.Select(p => p.CopyTo<SysRoleDto>()).ToList();
        }

        #endregion 用户的角色

        #region 用户的菜单

        public async Task<Dictionary<Guid, List<RoleMenuDto>>> GetUserMenus(Guid userId)
        {
            List<Guid> roleList = await GetUserRoles(userId);
            return await GetRoleMenus(roleList);
        }

        #endregion 用户的菜单

        #region 用户的权限

        /// <summary>
        /// 实时获取用户的角色，使用角色从缓存读取角色权限
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<RoleMenuPermissionDto>> GetUserPermissions(Guid userId)
        {
            List<Guid> roleList = await GetUserRoles(userId);
            return await GetRolePermissions(roleList);
        }

        #endregion 用户的权限

        #endregion 用户的角色 用户的菜单与权限

        /// <summary>
        /// 获取菜单树
        /// </summary>
        /// <returns></returns>
        public async Task<VMenu> GetMenuTree()
        {
            var list = await SysMenuRepository.GetMenuList();
            List<SysMenuFuncDto> menuFuncs = await GetMenuFuncs(new SysMenuFuncCondition());
            //获取所有的权限项目
            foreach (var v in list)//创建每个菜单的权限
            {
                v.MenuFuncs = menuFuncs.Where(p => p.MenuId == v.MenuId)
                    .Select(p => new VMenuFuncs()
                    {
                        AppId = p.AppId,
                        MenuId = p.MenuId,
                        MenuFuncId = p.MenuFuncId,
                        Component = p.Component,
                        Description = p.Description,
                        FuncName = p.Name,
                        Apis = p.Apis,
                    }).ToList();
            }

            return BuildTree(list);
        }

        /// <summary>
        /// 获取菜单功能
        /// </summary>
        /// <returns></returns>
        private async Task<List<SysMenuFuncDto>> GetMenuFuncs(SysMenuFuncCondition sysMenuFuncCondition)
        {
            var apiPageResult = await MenuFuncService.GetMenuFuncPage(sysMenuFuncCondition);
            var menuFuncs = apiPageResult.PageData as List<SysMenuFuncDto>;
            return menuFuncs;
        }

        public async Task<VMenu> GetRoleMenuTree(List<Guid> roleList)
        {
            List<VMenu> list = new List<VMenu>();
            Dictionary<Guid, List<RoleMenuDto>> dic = await GetRoleMenus(roleList);
            List<SysMenuFuncDto> menuFuncs = await GetMenuFuncs(new SysMenuFuncCondition() { RoleList = roleList });

            foreach (var roleMenu in dic)
            {
                foreach (var menu in roleMenu.Value)
                {
                    if (list.Where(p => p.MenuId == menu.MenuId).Count() == 0)
                    {
                        VMenu vMenu = CreateVMenu(menu);

                        vMenu.MenuFuncs = menuFuncs.Where(p => p.MenuId == vMenu.MenuId)
                                .Select(p => new VMenuFuncs()
                                {
                                    AppId = p.AppId,
                                    MenuId = p.MenuId,
                                    MenuFuncId = p.MenuFuncId,
                                    Component = p.Component,
                                    Description = p.Description,
                                    FuncName = p.Name,
                                    Apis = p.Apis,
                                }).ToList();

                        list.Add(vMenu);
                    }
                }
            }
            return BuildTree(list);
        }

        public async Task<VMenu> GetUserMenuTree(Guid userId)
        {
            List<VMenu> list = new List<VMenu>();
            Dictionary<Guid, List<RoleMenuDto>> dic = await GetUserMenus(userId);
            foreach (var roleMenu in dic)
            {
                foreach (var menu in roleMenu.Value)
                {
                    if (list.Where(p => p.MenuId == menu.MenuId).Count() == 0)
                    {
                        VMenu vMenu = CreateVMenu(menu);
                        list.Add(vMenu);
                    }
                }
            }
            return BuildTree(list.OrderBy(p => p.Level).OrderBy(p => p.Sort).ToList());
        }

        private static VMenu CreateVMenu(RoleMenuDto menu)
        {
            VMenu vMenu = new VMenu();
            vMenu.MenuId = menu.MenuId;
            vMenu.Name = menu.MenuName;
            vMenu.ParentId = menu.ParentMenuId;
            vMenu.ParentName = menu.ParentMenuName;
            vMenu.Level = menu.MenuLevel;
            vMenu.Sort = menu.MenuSort;
            vMenu.Url = menu.Url;
            vMenu.Component = menu.Component;

            return vMenu;
        }

        /// <summary>
        /// 返回树形结构的菜单
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private static VMenu BuildTree(List<VMenu> list)
        {
            VMenu root = new VMenu() { MenuId = Guid.Empty, Name = "Root" };
            if (list == null || list.Count == 0)
            {
                return root;
            }
            int maxLevel = list.Max(p => p.Level);
            List<VMenu> curLevelMenu = new List<VMenu>();
            List<VMenu> preLevelMenu = new List<VMenu>();
            for (int i = 0; i <= maxLevel; i++)
            {
                curLevelMenu = list.Where(p => p.Level == i).ToList();
                if (curLevelMenu.Count > 0)
                {
                    if (i == 0)
                    {
                        root.Menus = new List<VMenu>();
                        root.Menus.AddRange(curLevelMenu);
                        preLevelMenu = curLevelMenu;
                    }
                    else
                    {
                        foreach (var menu in curLevelMenu)
                        {
                            var parent = preLevelMenu.Where(p => p.MenuId == menu.ParentId).FirstOrDefault();
                            if (parent != null)
                            {
                                if (parent.Menus == null)
                                {
                                    parent.Menus = new List<VMenu>();
                                }
                                parent.Menus.Add(menu);
                            }
                        }

                        preLevelMenu = curLevelMenu;
                    }
                }
            }
            return root;
        }

        #endregion 添加人员到App角色、App的项目角色 角色权限 角色的菜单 用户的角色菜单与菜单权限
    }
}